package com.easylinkin.linkappapi.openapi.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.bases.redis.util.RedisUtil;
import com.easylinkin.linkappapi.annotation.CommonOperateLogAnnotate;
import com.easylinkin.linkappapi.application.entity.Application;
import com.easylinkin.linkappapi.application.service.ApplicationService;
import com.easylinkin.linkappapi.circuit.service.IRailGiveAlarmTypeConfigService;
import com.easylinkin.linkappapi.circuit.service.IRailLinkappAiHostRecordService;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.DigestUtil;
import com.easylinkin.linkappapi.config.service.ConfigService;
import com.easylinkin.linkappapi.danger.entity.DangerType;
import com.easylinkin.linkappapi.danger.entity.vo.DangerTypeNode;
import com.easylinkin.linkappapi.danger.service.DangerService;
import com.easylinkin.linkappapi.dashboard.service.DashboardService;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.elasticsearch.service.EtlStatisticMonitorService;
import com.easylinkin.linkappapi.elasticsearch.service.IEService;
import com.easylinkin.linkappapi.fillin.entity.vo.PeopleNumAtFillinVo;
import com.easylinkin.linkappapi.fillin.service.PeopleNumAtFillinService;
import com.easylinkin.linkappapi.function.entity.LinkappFunction;
import com.easylinkin.linkappapi.function.service.LinkappFunctionService;
import com.easylinkin.linkappapi.gaodemap.util.GaodeUtils;
import com.easylinkin.linkappapi.lobar.controller.app.enterprise.EnterpriseUserProjectController;
import com.easylinkin.linkappapi.lobar.dto.LaborCompanyProjectDTO;
import com.easylinkin.linkappapi.lobar.dto.UserProjectDTO;
import com.easylinkin.linkappapi.lobar.dto.app.EnterpriseDTO;
import com.easylinkin.linkappapi.lobar.dto.app.EpidemicDTO;
import com.easylinkin.linkappapi.lobar.dto.app.LobarUserDTO;
import com.easylinkin.linkappapi.lobar.service.LaborCompanyProjectService;
import com.easylinkin.linkappapi.lobar.service.LobarScreenService;
import com.easylinkin.linkappapi.lobar.service.UserProjectService;
import com.easylinkin.linkappapi.lobar.util.ProjectTenatUtils;
import com.easylinkin.linkappapi.openapi.dto.*;
import com.easylinkin.linkappapi.openapi.service.ApplicationCopyService;
import com.easylinkin.linkappapi.openapi.service.OpenApiService;
import com.easylinkin.linkappapi.openapi.service.SynchronizationLinkthingService;
import com.easylinkin.linkappapi.openapi.vo.SafetyCheckHiddenDangerPageVo;
import com.easylinkin.linkappapi.operatelog.constant.LogConstant.LogModule;
import com.easylinkin.linkappapi.personality.entity.Personality;
import com.easylinkin.linkappapi.personality.service.PersonalityService;
import com.easylinkin.linkappapi.quality.dto.QualityAppraisingExcellentPhotoAlbumDTO;
import com.easylinkin.linkappapi.quality.dto.QualityAppraisingExcellentPhotoAlbumQueryDTO;
import com.easylinkin.linkappapi.quality.dto.QualityPositionDTO;
import com.easylinkin.linkappapi.quality.entity.ActualMeasureItem;
import com.easylinkin.linkappapi.quality.entity.ActualMeasureType;
import com.easylinkin.linkappapi.quality.entity.Problem;
import com.easylinkin.linkappapi.quality.entity.ProblemType;
import com.easylinkin.linkappapi.quality.entity.vo.ActualMeasureItemVo;
import com.easylinkin.linkappapi.quality.entity.vo.ActualMeasureTypeVo;
import com.easylinkin.linkappapi.quality.entity.vo.QualityScreenPageVo;
import com.easylinkin.linkappapi.quality.mapper.ProblemMapper;
import com.easylinkin.linkappapi.quality.mapper.ProblemTypeMapper;
import com.easylinkin.linkappapi.quality.service.*;
import com.easylinkin.linkappapi.ruleengine.service.RuleEngineService;
import com.easylinkin.linkappapi.safe.dto.HiddenDangerCountDTO;
import com.easylinkin.linkappapi.safe.dto.HiddenDangerDTO;
import com.easylinkin.linkappapi.safe.entity.DangerousInfo;
import com.easylinkin.linkappapi.safe.entity.HiddenDanger;
import com.easylinkin.linkappapi.safe.service.HiddenDangerService;
import com.easylinkin.linkappapi.security.entity.LinkappPrivilege;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.service.LinkappPrivilegeService;
import com.easylinkin.linkappapi.security.service.LinkappUserService;
import com.easylinkin.linkappapi.space.entity.LinkappArea;
import com.easylinkin.linkappapi.space.mapper.LinkappAreaMapper;
import com.easylinkin.linkappapi.tenant.dto.LinkappTenantDTO;
import com.easylinkin.linkappapi.tenant.entity.LinkappTenant;
import com.easylinkin.linkappapi.tenant.entity.TenantRefPrivilege;
import com.easylinkin.linkappapi.tenant.entity.TenantRefPrivilegeDTO;
import com.easylinkin.linkappapi.tenant.mapper.LinkappTenantMapper;
import com.easylinkin.linkappapi.tenant.sevice.LinkappTenantService;
import com.easylinkin.sm.entity.User;
import com.easylinkin.sm.service.UserService;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@RestController
public class OpenApiController {
    /**
     * 缓存中 登录次数前缀
     */
    private final static String LOGIN_COUNT = "loginCount_";
    /**
     * -1标致 用户账号被锁
     */
    private final static Integer LOCKED_FLAG = -1;

    private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(OpenApiController.class);
    @Autowired
    ApplicationService applicationService;
    @Autowired
    LinkappPrivilegeService linkappPrivilegeService;
    @Autowired
    private PersonalityService personalityService;
    @Autowired
    private LinkappUserService userService;
    @Autowired
    private UserService userManagerService;
    @Autowired
    private LinkappTenantService linkappTenantService;

    @Autowired
    private LinkappFunctionService functionService;
    @Autowired
    private RuleEngineService ruleEngineService;

    @Resource
    private LinkappTenantMapper tenantMapper;
    @Resource
    private LinkappAreaMapper linkappAreaMapper;
    @Resource
    private DeviceMapper deviceMapper;
    @Resource
    private EtlStatisticMonitorService etlStatisticMonitorService;

    @Resource
    private SynchronizationLinkthingService synchronizationLinkthingService;

    @Resource
    private OpenApiService openApiService;
    @Resource
    ApplicationCopyService applicationCopyService;
    @Resource
    RedisUtil redisUtil;
    @Resource
    IEService esService;
    @Resource
    LinkappUserService linkappUserService;


    @Resource
    private ConfigService configService;
    @Autowired
    private ProblemTypeMapper problemTypeMapper;
    @Autowired
    private ProblemMapper problemMapper;
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private CommonService commonService;

    @Resource
    private HiddenDangerService hiddenDangerService;

    @Autowired
    private LaborCompanyProjectService laborCompanyProjectService;

    @Resource
    private DangerService appDangerService;

    @Autowired
    private QualityPositionService qualityPositionService;

    @Resource
    private PeopleNumAtFillinService appPeopleNumAtFillinService;

    @Autowired
    private LobarScreenService lobarScreenService;

    @Autowired
    private UserProjectService userProjectService;

    @Resource
    private ActualMeasureTypeService actualMeasureTypeService;

    @Resource
    private ActualMeasureItemService actualMeasureItemService;

    @Resource
    private QualityInspectionAccountService qualityInspectionAccountService;

    @Resource
    private QualityQuestionInfoService qualityQuestionInfoService;

    @Autowired
    private QualityAppraisingExcellentService qualityAppraisingExcellentService;

    @Resource
    private DashboardService dashboardService;
    @Autowired
    private IRailGiveAlarmTypeConfigService railGiveAlarmTypeConfigService;

    @Autowired
    private IRailLinkappAiHostRecordService railLinkappAiHostRecordService;
    /**
     * 查找linkthings 活动的应用； 同步修改AEP的租户状态
     * <p>getActiveApp 接口名最好改成synchronizeTenantStatusFromLinkthings 更符合</p>
     */
    @ApiOperation("查找linkthings活动的应用")
    @RequestMapping(value = "/getActiveApp", produces = "application/json;charset=UTF-8")
    public RestMessage getActiveApp() {
        try {
            openApiService.synchronizeTenantStatusFromLinkthings();
            return RestBuilders.successBuilder("200").build();
        } catch (UnsupportedEncodingException e) {
            return RestBuilders.failureBuilder().code("500").build();
        }
    }

    @ApiOperation("同步平台信息")
    @RequestMapping(value = "/getTenantInfo", produces = "application/json;charset=UTF-8")
    @CommonOperateLogAnnotate(module = LogModule.TENANT, desc = "同步平台信息")
    public RestMessage getTenantInfo() {
        Boolean synchronizationLinkthing = true;
        try {
            openApiService.getTenantInfo();
        } catch (UnsupportedEncodingException e) {
            synchronizationLinkthing = false;
        }
        return RestBuilders.successBuilder(synchronizationLinkthing).build();
    }

    @ApiOperation("通过应用认证获取所有菜单类型数据")
    @PostMapping("/selectAllPrivilegeByApplication")
    public RestMessage selectAllPrivilegeByApplication(HttpServletRequest request, HttpServletResponse response,
                                                       @RequestParam("requestId") String requestId) {
        String signToString = requestId;
        return checkAuth(request, signToString,() ->{
            LinkappPrivilege linkappPrivilege = new LinkappPrivilege();
            linkappPrivilege.setType(1);
            List<LinkappPrivilege> linkappPrivilegeList = linkappPrivilegeService.selectPrivilegeAll(linkappPrivilege);
            return RestBuilders.successBuilder(linkappPrivilegeList).build();
        });
    }

    @ApiOperation("通过应用认证获取用户的菜单类型数据")
    @PostMapping("/selectPrivilegeByApplication")
    public RestMessage selectPrivilegeByApplication(HttpServletRequest request, HttpServletResponse response,
                                                    @RequestParam("requestId") String requestId,
                                                    @RequestParam("appkey") String appkey,
                                                    @RequestParam("account") String account) {
        String signToString = requestId + "-" + appkey + "-" + account;
        return checkAuth(request, signToString,() ->{
            LinkappUser user = userService.findByUsername(account);
            List<LinkappPrivilege> linkappPrivilegeList = applicationService.selectApplicationPrivilegeMenuByUser(user.getId() + "");
            return RestBuilders.successBuilder(linkappPrivilegeList).build();
        });
    }

    @ApiOperation("通过应用认证获取用户个性化设置信息")
    @PostMapping("/selectPersonalityByApplication")
    public RestMessage selectPersonalityByApplication(HttpServletRequest request, HttpServletResponse response,
                                                      @RequestParam("requestId") String requestId,
                                                      @RequestParam("appkey") String appkey,
                                                      @RequestParam("account") String account) {
        String signToString = requestId + "-" + appkey + "-" + account;
        return checkAuth(request, signToString,() ->{
            LinkappUser query = new LinkappUser();
            query.setUsername(account);
            List<LinkappUser> users = userService.selectUsers(query);
            if (ObjectUtils.isEmpty(users)) {
                LOGGER.info("selectPersonalityByApplication根据username查询用户为空，account：" + account);
                return RestBuilders.failureBuilder("认证失败,根据username查询用户为空").build();
            }
            LinkappUser user = users.get(0);
            LinkappTenant tenant = new LinkappTenant();
            tenant.setId(user.getTenantId());
            tenant = linkappTenantService.selectLinkappTenant(tenant);
            if (tenant != null) {
                Personality personality = personalityService.getById(tenant.getPersonalityId());
                return RestBuilders.successBuilder(personality).build();
            } else {
                return RestBuilders.failureMessage();
            }
        });
    }

    @ApiOperation("获取免密登录地址")
    @PostMapping("/openapi/getSSOUrl")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "通过应用修改个性化权限")
    public RestMessage getSSOUrl(@RequestBody LinkappUser user) {
        return RestBuilders.successBuilder().data(linkappTenantService.getSSOUrl(user)).build();
    }


    @ApiOperation("通过应用修改个性化权限")
    @PostMapping("/updatePrivilegePersonalityByApplication")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "通过应用修改个性化权限")
    public RestMessage updatePrivilegePersonalityByApplication(HttpServletRequest request, HttpServletResponse response,
                                                               @RequestBody TenantInfoDTO tenantInfoDTO) {
        String signToString = tenantInfoDTO.getRequestId() + "-" + tenantInfoDTO.getAppkey() + "-" + tenantInfoDTO.getAccount();
        return checkAuth(request, signToString,() ->{
            LinkappUser user = userService.findByUsername(tenantInfoDTO.getAccount());
            LinkappTenant tenant = new LinkappTenant();
            tenant.setId(user.getTenantId());
            tenant = linkappTenantService.selectLinkappTenant(tenant);

            if (tenant.getPersonalityId() != null) {
                Personality personalityQuery = personalityService.getById(tenant.getPersonalityId());
                if (personalityQuery != null) {
                    Personality personality = tenantInfoDTO.getPersonality();
                    personality.setId(personalityQuery.getId());
//                    personality.setModifyTime(new Date());
//                    personalityService.updateById(personality);
                    personalityService.updatePersonality(personality);
                }
            }

            List<LinkappPrivilege> privileges = tenantInfoDTO.getPrivileges();
            List<LinkappPrivilege> nodePrivileges = new ArrayList<LinkappPrivilege>();
            for (LinkappPrivilege privilege : privileges) {
                LinkappPrivilege privilegeQuery = new LinkappPrivilege();
                privilegeQuery.setParentId(privilege.getId());
                privilegeQuery.setType(2);
                List<LinkappPrivilege> privilegeQuerys = linkappPrivilegeService.selectPrivilegeAll(privilegeQuery);
                if (!privilegeQuerys.isEmpty()) {
                    nodePrivileges.addAll(privilegeQuerys);
                }
            }
            privileges.addAll(nodePrivileges);
            TenantRefPrivilegeDTO tenantRefPrivilegeDTO = new TenantRefPrivilegeDTO();
            tenantRefPrivilegeDTO.setTenant(tenant);
            tenantRefPrivilegeDTO.setPrivileges(privileges);
            linkappTenantService.tenant2Privileges(tenantRefPrivilegeDTO);
            return RestBuilders.successBuilder("修改成功").build();
        });
    }

    @ApiOperation("通过应用认证获取所有功能模块数据")
    @PostMapping("/openapi/function/selectAllFunction")
    public RestMessage selectAllFunction(HttpServletRequest request, HttpServletResponse response,
                                         @RequestParam("requestId") String requestId) {
        String signToString = requestId;
        return checkAuth(request, signToString,() ->{
            LinkappFunction function = new LinkappFunction();
            List<LinkappFunction> functions = functionService.getLinkappFunctions(function);
            return RestBuilders.successBuilder(functions).build();
        });
    }

    /**
     * 此方法被linkthings的 api/appBuyList/selectPrivilege接口内部调用
     * @param request
     * @param requestId
     * @param account
     * @return
     */
    @ApiOperation("通过应用认证获取租户的功能模块数据")
    @PostMapping("/openapi/function/selectFunctionsByTenant")
    public RestMessage selectAllPrivilegeByFunction(HttpServletRequest request,
                                                    @RequestParam("requestId") String requestId, @RequestParam("account") String account) {
        String appkey = request.getHeader("H-App-Key").trim();
        String signToString = requestId + "-" + appkey + "-" + account;
        return checkAuth(request, signToString,() ->{
            LinkappUser user = userService.findByUsername(account);
            LinkappFunction function = new LinkappFunction();
            function.setTenantId(user.getTenantId());
            List<LinkappFunction> functions = functionService.getLinkappFunctions(function);
            return RestBuilders.successBuilder(functions).build();
        });
    }

    @ApiOperation("修改功能权限")
    @PostMapping("/openapi/function/updateFunctionsByTenant")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "修改功能权限")
    public RestMessage updateFunctionsByTenant(HttpServletRequest request, HttpServletResponse response,
                                                 @RequestBody FunctionInfoDTO functionDTO) {
        LOGGER.info("/openapi/function/updateFunctionsByTenant被调用，functionDTO参数是 : {}", JSONObject.toJSONString(functionDTO));
        String headerSign = request.getHeader("H-Ca-Signature");
        Assert.hasLength(headerSign, "请求头头参数H-Ca-Signature为空");
        String signToString = functionDTO.getRequestId() + "-" + functionDTO.getAppkey() + "-" + functionDTO.getAccount();

        return checkAuth(request, signToString,() ->{
            LinkappUser user = userService.findByUsername(functionDTO.getAccount());

            if (user != null) {
                if (null != functionDTO.getFunctions() && functionDTO.getFunctions().size() > 0) {
                    functionService.functions2Tenant(user.getTenantId(), functionDTO.getFunctions());

                    List<LinkappPrivilege> linkappPrivilegeList = new ArrayList<LinkappPrivilege>();
                    for (LinkappFunction function : functionDTO.getFunctions()) {
                        if (function.getId() != null) {
                            List<LinkappPrivilege> list = functionService.selectPrivilegeByFunction(function.getId());
                            linkappPrivilegeList.addAll(list);
                        }
                    }
                    tenantMapper.deleteTenant2Privileges(user.getTenantId(), 0);
                    for (LinkappPrivilege privilege : linkappPrivilegeList) {
                        TenantRefPrivilege tenantRefPrivilege = new TenantRefPrivilege();
                        tenantRefPrivilege.setId(UUID.randomUUID().toString().replaceAll("-", ""));
                        tenantRefPrivilege.setTenantId(user.getTenantId());
                        tenantRefPrivilege.setPrivilegeId(privilege.getId() + "");
                        tenantMapper.insertTenant2Privileges(tenantRefPrivilege);
                    }
                }
                if (functionDTO.getPersonality() != null && !functionDTO.getPersonality().isAllEmpty()) {
                    LinkappTenant tenant = new LinkappTenant();
                    tenant.setId(user.getTenantId());
                    tenant = linkappTenantService.selectLinkappTenant(tenant);
                    Assert.notNull(tenant, "查询得租户为空:id:" + user.getTenantId());
                    boolean updatePersonalityResult = false;
                    if (tenant.getPersonalityId() != null) {
                        Personality personalityQuery = personalityService.getById(tenant.getPersonalityId());
                        if (personalityQuery != null) {
                            Personality personality = functionDTO.getPersonality();
                            personality.setId(personalityQuery.getId());
                            updatePersonalityResult = personalityService.updatePersonality(personality);
                            LOGGER.info("修改功能权限修改成功423267！");
                        }
                    }
                    if(!updatePersonalityResult){
                        Personality personality = functionDTO.getPersonality();
                        personality.setCreateTime(new Date());
                        personalityService.addPersonality(personality, user.getTenantId());
                        LOGGER.info("修改功能权限保存成功423267！");
                    }
                }
                LOGGER.info("修改功能权限调用成功423267！");
                return RestBuilders.successBuilder("修改成功").build();
            } else {
                LOGGER.info("修改功能权限保存失败423267！user为空");
                return RestBuilders.failureBuilder("保存失败").build();
            }
        });
    }

    @ApiOperation("查询功能关联的权限菜单")
    @PostMapping("/openapi/function/selectPrivilegeByFunction")
    public RestMessage selectPrivilegeByFunction(HttpServletRequest request, HttpServletResponse response,
                                                 @RequestParam("requestId") String requestId,
                                                 @RequestParam("appkey") String appkey,
                                                 @RequestParam("functionId") String functionId) {
        String signToString = requestId + "-" + appkey + "-" + functionId;
        return checkAuth(request, signToString,() ->{
            List<LinkappPrivilege> linkappPrivilegeList = functionService.selectPrivilegeByFunction(functionId);
            return RestBuilders.successBuilder(linkappPrivilegeList).build();
        });
    }

    @ApiOperation("初始化租户")
    @PostMapping("/openapi/function/initLinkappTenantByFunction")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "初始化租户")
    public Map<String, String> initLinkappTenant(HttpServletRequest request, HttpServletResponse response,
                                                 @RequestBody FunctionInfoDTO functionInfoDTO) {
        Map<String, String> map = new HashMap<String, String>();
        String headerSign = request.getHeader("H-Ca-Signature").trim();
        LOGGER.info("initLinkappTenantByFunction_JSON functionInfoDTO : " + JSON.toJSONString(functionInfoDTO));
        String signToString = functionInfoDTO.getRequestId() + "-" + functionInfoDTO.getAppkey() + "-" + functionInfoDTO.getPlatformProjectName()
                + "-" + functionInfoDTO.getPlatformAccount() + "-" + functionInfoDTO.getPlatformAccountName() + "-" + functionInfoDTO.getAppIndustryType();
        QueryWrapper<Application> wrapper = new QueryWrapper<>();
        wrapper.eq("app_key", functionInfoDTO.getAppkey());
        wrapper.eq("delete_state", 1);
        Application application = applicationService.getApplication(wrapper);
        String sign = DigestUtil.hmacSHA256Sign(signToString, application.getAppSecret()).trim();

        LOGGER.info("initLinkappTenantByFunction_headerSign : " + headerSign);
        LOGGER.info("initLinkappTenantByFunction_appkey : " + functionInfoDTO.getAppkey());
        LOGGER.info("initLinkappTenantByFunction_signToString : " + signToString);
        LOGGER.info("initLinkappTenantByFunction_sign : " + sign);

        if (sign.equalsIgnoreCase(headerSign)) {
            LinkappTenant tenant = linkappTenantService.initLinkappTenantByFunction(functionInfoDTO);
            LOGGER.info("initLinkappTenantByFunction list=" + JSON.toJSONString(tenant));
            if (tenant == null) {
                map.put("code", "500");
                map.put("message", "创建异常");
                LOGGER.info("创建异常");
            } else {
                map.put("code", "200");
                map.put("message", "success");
                map.put("saasTenantId", tenant.getId());
                map.put("initAccount", tenant.getInitAccount());
                LOGGER.info("创建成功");
//                if(functionInfoDTO.getEnableAsyncInitDevices() == null || !functionInfoDTO.getEnableAsyncInitDevices()){
//                    //AEP初始化设备同步--同步调用
//                    try {
//                        //同步设备型号
//                        synchronizationLinkthingService.synchronizeDeviceUnitByProject(tenant);
//                        //同步设备
//                        synchronizationLinkthingService.getDevicesByProject(tenant);
//                    } catch (UnsupportedEncodingException e) {
//                        map=new HashMap<String, String>();
//                        map.put("code", "500");
//                        map.put("message", "同步设备异常");
//                        return map;
//                    }
//                }else{
//                    //AEP初始化设备同步--异步调用
//                    synchronizationLinkthingService.syncDeviceAndUnitByProject(request, tenant);
//                }

                //20220729新增逻辑：复制一份配置中心的配置到新租户
                LinkappTenant oldTenant = linkappTenantService.getLastHasConfigOne();
                configService.copyLastConfigToNewTenant(oldTenant,tenant);

                //为新项目创建一份新的问题分类
                setProblem(tenant);

                //20220901为新项目创建一份新的实测实量数据
                commonService.copyActualMeasureTypeItem(tenant);

                //创建大屏配置
                dashboardService.createIfNotExist(tenant);

                //初始化所有告警配置
                railGiveAlarmTypeConfigService.initAllConfig(tenant.getId());

            }
        } else {
            map.put("code", "501");
            map.put("message", "认证失败");
        }
        return map;
    }


    /**
     * 为新项目初始化问题
     * @param tenant
     */
    private void setProblem(LinkappTenant tenant) {
        //分类
        QueryWrapper<ProblemType> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.isNull("tenant_id_");
        List<ProblemType> problemTypes = problemTypeMapper.selectList(queryWrapper1);
        //问题库
        QueryWrapper<Problem> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.isNull("tenant_id_");
        List<Problem> problems = problemMapper.selectList(queryWrapper2);
        problemTypes.forEach(p ->{
            ProblemType problemType = BeanUtil.toBean(p, ProblemType.class);
            problemType.setSrcId(p.getId());
            problemType.setId(null);
            problemType.setTenantId(tenant.getId());
            problemTypeMapper.insert(problemType);
        });
        problems.forEach(p->{
            Problem problem = BeanUtil.toBean(p, Problem.class);
            problem.setSrcId(p.getId());
            problem.setId(null);
            problem.setTenantId(tenant.getId());
            problemMapper.insert(problem);
        });
        jdbcTemplate.execute("UPDATE app_problem_type a\n"
            + "left JOIN app_problem_type b\n"
            + "on a.parent_id_ = b.src_id_ and a.tenant_id_ = b.tenant_id_\n"
            + "set a.parent_id_ = b.id\n"
            + "WHERE a.level_ = 2 and a.tenant_id_ = '" + tenant.getId() +"'");

        jdbcTemplate.execute("UPDATE app_problem a\n"
            + "LEFT JOIN app_problem_type b ON a.tenant_id_ = b.tenant_id_ \n"
            + "AND a.problem_type_id_ = b.src_id_ \n"
            + "SET a.problem_type_id_ = b.id \n"
            + "WHERE\n"
            + "\ta.tenant_id_ = '" + tenant.getId() +"'");
    }

    @ApiOperation("修改项目信息")
    @PostMapping("/openapi/project/update")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "修改项目信息")
    public RestMessage initLinkappTenant(@RequestBody ProjectDTO projectDTO) {
        List<LinkappTenant> tenants = tenantMapper
            .selectByProjectId(String.valueOf(projectDTO.getId()));
        if (null != tenants && tenants.size() > 0){
            LinkappTenant linkappTenant = tenants.get(0);

            // 旧建设状态
            Integer oldProjectStatus = linkappTenant.getProjectStatus();

            linkappTenant.setPlatformProjectName(projectDTO.getName());
            //预计开工时间
            linkappTenant.setEstimateTime(projectDTO.getEstimateTime());
            //预计完工时间
            linkappTenant.setCompletionTime(projectDTO.getCompletionTime());
            //建设单位
            linkappTenant.setConstructionUnit(projectDTO.getConstructionUnit());
            //招标单位
            linkappTenant.setBiddingUnit(projectDTO.getBiddingUnit());
            //项目地点
            linkappTenant.setLocation(projectDTO.getLocation());
            linkappTenant.setProjectDesc(projectDTO.getProjectDesc());
            linkappTenant.setArea(projectDTO.getArea());
            //项目类型
            linkappTenant.setProjectType(projectDTO.getProjectType());
            //项目状态
            linkappTenant.setProjectStatus(projectDTO.getProjectStatus());
            //实际开工时间
            linkappTenant.setActualStartTime(projectDTO.getActualStartTime());
            //实际完工时间
            linkappTenant.setActualCompletionTime(projectDTO.getActualCompletionTime());
            //项目金额
            linkappTenant.setProjectAmount(projectDTO.getProjectAmount());
            //施工单位
            linkappTenant.setShigongUnit(projectDTO.getShigongUnit());
            //设计单位
            linkappTenant.setDesignUnit(projectDTO.getDesignUnit());
            //监理单位
            linkappTenant.setConstructionControlUnit(projectDTO.getConstructionControlUnit());
            //勘查单位
            linkappTenant.setExplorationUnit(projectDTO.getExplorationUnit());
            //项目区域
            linkappTenant.setProjectArea(projectDTO.getProjectArea());
            //质量创优等级
            linkappTenant.setQualityExcellenceLevel(projectDTO.getQualityExcellenceLevel());
            //安全创优等级
            linkappTenant.setSafetyExcellenceLevel(projectDTO.getSafetyExcellenceLevel());
            //项目经纬度
            linkappTenant.setLongitude(projectDTO.getLongitude());
            linkappTenant.setLatitude(projectDTO.getLatitude());
            linkappTenant.setProjectManager(projectDTO.getProjectManager());
            linkappTenant.setProjectManagerPhone(projectDTO.getProjectManagerPhone());
            linkappTenant.setTechEngineer(projectDTO.getTechEngineer());
            linkappTenant.setTechEngineerPhone(projectDTO.getTechEngineerPhone());
            linkappTenant.setProductManager(projectDTO.getProductManager());
            linkappTenant.setProductManagerPhone(projectDTO.getProductManagerPhone());
            linkappTenant.setQualityGoalAward(projectDTO.getQualityGoalAward());
            linkappTenant.setSafeExcellenceAward(projectDTO.getSafeExcellenceAward());
            linkappTenant.setProjectArchiveNo(projectDTO.getProjectArchiveNo());
            linkappTenant.setProjectImgUrl(projectDTO.getProjectImgUrl());
            linkappTenant.setProjectVideoUrl(projectDTO.getProjectVideoUrl());
            linkappTenant.setProjectShortName(projectDTO.getProjectShortName());
            linkappTenant.setProjectCrossType(projectDTO.getProjectCrossType());
            linkappTenant.setProjectConfirmTime(projectDTO.getProjectConfirmTime());
            linkappTenant.setProjectInitConfirmTime(projectDTO.getProjectInitConfirmTime());
            linkappTenant.setProjectDesignConfirmTime(projectDTO.getProjectDesignConfirmTime());
            linkappTenant.setProjectPlanDuration(projectDTO.getProjectPlanDuration());
            linkappTenant.setProjectBuildUnit(projectDTO.getProjectBuildUnit());
            linkappTenant.setProjectShigongUnitLeader(projectDTO.getProjectShigongUnitLeader());
            linkappTenant.setProjectLine(projectDTO.getProjectLine());
            linkappTenant.setProjectIntervalDistance(projectDTO.getProjectIntervalDistance());
            linkappTenant.setProjectProgress(projectDTO.getProjectProgress());
            linkappTenant.setProjectTransport(projectDTO.getProjectTransport());
            linkappTenant.setProjectProblem(projectDTO.getProjectProblem());
            linkappTenant.setProjectPaidAmount(projectDTO.getProjectPaidAmount());
            linkappTenant.setProjectContractDuration(projectDTO.getProjectContractDuration());
            linkappTenant.setBelongArea(projectDTO.getBelongArea());
            // 如果状态切换为停工，存储剩余天数、进度等字段
            if (ProjectTenatUtils.projectSuspendedStatusList.contains(projectDTO.getProjectStatus()) && !Objects.equals(projectDTO.getProjectStatus(), oldProjectStatus)) {
                LinkappTenantDTO linkappTenantDTO = new LinkappTenantDTO();
                BeanUtil.copyProperties(linkappTenant, linkappTenantDTO);
                // 用旧状态计算
                linkappTenantDTO.setProjectStatus(oldProjectStatus);

                ProjectTenatUtils.calculateProgress(linkappTenantDTO);
                linkappTenant.setProgressUponSuspension(linkappTenantDTO.getProgress());

                ProjectTenatUtils.calculateSurplusDay(linkappTenantDTO);
                linkappTenant.setSurplusDayUponSuspension(linkappTenantDTO.getSurplusDay());

                linkappTenant.setStatusChangeTimeUponSuspension(new Date());
            }
            tenantMapper.updateById(linkappTenant);
            return RestBuilders.successBuilder("修改成功").build();
        }
        LOGGER.error("查询不到对应租户根据项目id:" + projectDTO.getId());
        return RestBuilders.failureBuilder("查询不到对应租户根据项目id:" + projectDTO.getId()).build();
    }

    @ApiOperation("修改租户信息")
    @PostMapping("/openapi/tenant/updateTenantInfo")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "修改租户信息")
    public RestMessage updateTenantInfo(HttpServletRequest request, HttpServletResponse response,
                                        @RequestBody UpateTenantInfoDTO tenantInfoDTO) {
        String signToString = tenantInfoDTO.getRequestId() + "-" + tenantInfoDTO.getAppkey();
        return checkAuth(request, signToString,() ->{
            UpdateWrapper<LinkappTenant> updateWrapper = new UpdateWrapper<LinkappTenant>();
            updateWrapper.eq("app_id", tenantInfoDTO.getAppId());
            updateWrapper.set("tenant_id", tenantInfoDTO.getTenantId());
            updateWrapper.set("project_id", tenantInfoDTO.getProjectId());
            updateWrapper.set("name", tenantInfoDTO.getName());
            updateWrapper.set("app_type", tenantInfoDTO.getVipType());
            updateWrapper.set("platform_project_name", tenantInfoDTO.getPlatformProjectName());
            updateWrapper.set("platform_account", tenantInfoDTO.getPlatformAccount());
            updateWrapper.set("platform_account_name", tenantInfoDTO.getPlatformAccountName());
            updateWrapper.set("app_industry_type", tenantInfoDTO.getAppIndustryType());
            updateWrapper.set("email", tenantInfoDTO.getEmail());
            updateWrapper.set("telephone", tenantInfoDTO.getTelephone());
            linkappTenantService.update(updateWrapper);
            return RestBuilders.successBuilder("修改成功").build();
        });
    }

    @ApiOperation("根据用户账号修改租户菜单权限")
    @PostMapping("/updatePrivilegeByFunction")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "updatePrivilegeByFunction")
    public RestMessage updatePrivilegeByFunction(HttpServletRequest request, HttpServletResponse response,
                                                 @RequestBody TenantInfoDTO tenantInfoDTO) {
        String signToString = tenantInfoDTO.getRequestId() + "-" + tenantInfoDTO.getAppkey() + "-" + tenantInfoDTO.getAccount();
        return checkAuth(request, signToString,() ->{
            LinkappUser user = userService.findByUsername(tenantInfoDTO.getAccount());
            LinkappTenant tenant = new LinkappTenant();
            tenant.setId(user.getTenantId());
            tenant = linkappTenantService.selectLinkappTenant(tenant);
            Personality personalityQuery = personalityService.getById(tenant.getPersonalityId());
            Personality personality = tenantInfoDTO.getPersonality();
            personality.setId(personalityQuery.getId());
//            personality.setModifyTime(new Date());
//            personalityService.updateById(personality);
            personalityService.updatePersonality(personality);
            List<LinkappPrivilege> privileges = tenantInfoDTO.getPrivileges();
            List<LinkappPrivilege> nodePrivileges = new ArrayList<LinkappPrivilege>();
            for (LinkappPrivilege privilege : privileges) {
                LinkappPrivilege privilegeQuery = new LinkappPrivilege();
                privilegeQuery.setParentId(privilege.getId());
                privilegeQuery.setType(2);
                List<LinkappPrivilege> privilegeQuerys = linkappPrivilegeService.selectPrivilegeAll(privilegeQuery);
                if (!privilegeQuerys.isEmpty()) {
                    nodePrivileges.addAll(privilegeQuerys);
                }
            }
            privileges.addAll(nodePrivileges);
            TenantRefPrivilegeDTO tenantRefPrivilegeDTO = new TenantRefPrivilegeDTO();
            tenantRefPrivilegeDTO.setTenant(tenant);
            tenantRefPrivilegeDTO.setPrivileges(privileges);
            linkappTenantService.tenant2Privileges(tenantRefPrivilegeDTO);
            return RestBuilders.successBuilder("修改成功").build();
        });
    }

    @ApiOperation("初始化租户")
    @PostMapping("/initLinkappTenant")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "初始化租户")
    public Map<String, String> initLinkappTenant(HttpServletRequest request, HttpServletResponse response,
                                                 @RequestBody TenantInfoDTO tenantInfoDTO) {
        Map<String, String> map = new HashMap<String, String>();
        String headerSign = request.getHeader("H-Ca-Signature").trim();
        String signToString = tenantInfoDTO.getRequestId() + "-" + tenantInfoDTO.getAppkey() + "-" + tenantInfoDTO.getPlatformProjectName()
                + "-" + tenantInfoDTO.getPlatformAccount() + "-" + tenantInfoDTO.getPlatformAccountName() + "-" + tenantInfoDTO.getAppIndustryType();
        QueryWrapper<Application> wrapper = new QueryWrapper<>();
        wrapper.eq("app_key", tenantInfoDTO.getAppkey());
        wrapper.eq("delete_state", 1);
        Application application = applicationService.getApplication(wrapper);
        String sign = DigestUtil.hmacSHA256Sign(signToString, application.getAppSecret()).trim();
        LOGGER.info("headerSign : " + headerSign);
        LOGGER.info("appkey : " + tenantInfoDTO.getAppkey());
        LOGGER.info("signToString : " + signToString);
        LOGGER.info("sign : " + sign);

        if (sign.equalsIgnoreCase(headerSign)) {
            LinkappTenant tenant = linkappTenantService.initLinkappTenant(tenantInfoDTO);
            if (tenant == null) {
                map.put("code", "500");
                map.put("message", "创建异常");
            } else {
                map.put("code", "200");
                map.put("message", "success");
                map.put("saasTenantId", tenant.getId());
                map.put("initAccount", tenant.getInitAccount());

                //AEP初始化设备同步--异步调用
                synchronizationLinkthingService.syncDeviceAndUnitByProject(request, tenant);
            }
        } else {
            map.put("code", "501");
            map.put("message", "认证失败");
        }
        return map;
    }


    /**
     * 锁定
     *
     * @return REST消息
     */
    @ApiOperation("锁定用户")
    @PostMapping("/lock")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "锁定用户")
    public RestMessage lock(HttpServletRequest request, HttpServletResponse response,
                            @RequestParam("requestId") String requestId,
                            @RequestParam("appkey") String appkey,
                            @RequestParam("usernames") String usernames) {
        String signToString = requestId + "-" + appkey;
        return checkAuth(request, signToString,() ->{
            //租户ID去重
            Set<String> tenantIds = new HashSet<String>();
            //usernames去重
            List<String> usernameList = Arrays.stream(usernames.split(",")).distinct().collect(Collectors.toList());

            int size = usernameList.size();
            int baseNum = 50;
            int sunSum = GaodeUtils.getLoopCount(size, baseNum);
            int listStart, listEnd;
            for (int i = 1; i <= sunSum; i++) {
                listStart = (i - 1) * baseNum;
                listEnd = listStart + baseNum;
                if (i == sunSum) {
                    listEnd = size;
                }
//				List<Long> ids = new ArrayList<Long>();
                List<String> subUserNameList = usernameList.subList(listStart, listEnd);
                List<LinkappUser> userList = userService.findByUsernameBatch(subUserNameList);
                for (LinkappUser user : userList) {
                    if (user != null) {
//						ids.add(user.getId());
                        tenantIds.add(user.getTenantId());
                    }
                }
//				没必要执行lockAll操作
//				if (!ids.isEmpty()) {
//					userService.lockAll(ids);
//                }
            }

            List<String> tenantIdList = new ArrayList<>(tenantIds);
            if (!tenantIds.isEmpty()) {
                LOGGER.info("租户ID：{}", tenantIdList);
                userService.tenantLock(tenantIdList);
            }
            return RestBuilders.successMessage();
        });
    }

    /**
     * 解锁
     *
     * @return REST消息
     */
    @ApiOperation("解锁用户")
    @PostMapping("/unlock")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "解锁用户")
    public RestMessage unlock(HttpServletRequest request, HttpServletResponse response,
                              @RequestParam("requestId") String requestId,
                              @RequestParam("appkey") String appkey,
                              @RequestParam("usernames") String usernames) {
        String signToString = requestId + "-" + appkey;
        return checkAuth(request, signToString,() ->{
            List<Long> ids = new ArrayList<Long>();
            String[] usernameList = usernames.split(",");
            for (String username : usernameList) {
                LinkappUser user = userService.findByUsername(username);
                if (user != null) {
                    ids.add(user.getId());
                    ruleEngineService.enableByTenantId(user.getTenantId());
                }
            }
            if (!ids.isEmpty()) {
                userService.unlockAll(ids);
            }
            return RestBuilders.successMessage();
        });
    }

    @ApiOperation("根据条件获取空间区域数据")
    @PostMapping("/openapi/selectLinkappAreaTreeList")
    public RestMessage selectLinkappAreaTreeList(HttpServletRequest request, HttpServletResponse response,
                                                 @RequestBody LinkappArea linkappArea) {
        if (linkappArea == null) {
            linkappArea = new LinkappArea();
        }
        return RestBuilders.successBuilder(linkappAreaMapper.selectLinkappAreaTreeList(linkappArea)).build();
    }

    @ApiOperation("根据条件获取设备详细信息")
    @PostMapping("/openapi/device/get")
    public RestMessage getDevices(HttpServletRequest request, HttpServletResponse response,
                                  @RequestBody Device device) {
        if (device == null) {
            device = new Device();
        }
        //update by kanyuanfeng 20201014 父区域也可以查询子区域的设备
        String areaId = device.getAreaId();
        if (StringUtils.isNotBlank(areaId)) {
            LinkappArea linkappArea = new LinkappArea();
            linkappArea.setParentId(areaId);
            List<LinkappArea> linkappAreaList = linkappAreaMapper.selectLinkappAreaList(linkappArea);
            //获取区域id集合
            List<String> areaIds = linkappAreaList.stream().map(l -> l.getId())
                    .collect(Collectors.toList());
            //添加自己本身areaId
            areaIds.add(areaId);
            device.setAreaIds(areaIds);
            device.setAreaId(null);
        }
        return RestBuilders.successBuilder(deviceMapper.selectDevices(device)).build();
    }

    @ApiOperation("批量新增设备")
    @PostMapping("/openapi/device/addDevices")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "批量新增设备")
    public RestMessage addDevices(HttpServletRequest request, HttpServletResponse response,
                                  @RequestBody List<Device> deviceList) {
        openApiService.addDevices(deviceList);
        return RestBuilders.successBuilder().build();
    }

    @ApiOperation("批量删除设备")
    @PostMapping("/openapi/device/deleteDevices")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "批量删除设备")
    public RestMessage deleteDevices(HttpServletRequest request, HttpServletResponse response,
                                     @RequestBody Set<String> deviceCodes) {
        openApiService.batchEraseDevicePositionEtcInfo(deviceCodes);
        return RestBuilders.successBuilder().build();
    }


    /**
     * 擦除设备位置信息
     */
    @ApiOperation("擦除设备位置信息")
    @PostMapping("/openapi/device/batchEraseDevicePositionEtcInfo")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "擦除设备位置信息")

    public RestMessage batchEraseDevicePositionEtcInfo(HttpServletRequest request, HttpServletResponse response,
                                                       @RequestBody Set<String> deviceCodes) {
        openApiService.batchEraseDevicePositionEtcInfo(deviceCodes);
        return RestBuilders.successBuilder().build();
    }

    @ApiOperation("内部解锁")
    @GetMapping(value = {"/openapi/inner-unlock/{username}", "/openapi/inner-unlock/{manage}/{username}"})
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "内部解锁")
    public RestMessage innerUnlock(@PathVariable(value = "username") String username, @PathVariable(value = "manage", required = false) String manage) {
        if (StringUtils.isEmpty(username)) {
            return RestBuilders.failureMessage().setMessage("username 为空");
        }
        if (StringUtils.isEmpty(manage)) {
            //用户
            LinkappUser linkappUser = userService.findByUsername(username);
            if (linkappUser == null || linkappUser.getId() == null) {
                return RestBuilders.failureMessage().setMessage("用户不存在");
            }
            userService.unlock(linkappUser.getId());
        } else {
            //管理员
            User user = userManagerService.findByUsername(username);
            if (user == null || user.getId() == null) {
                return RestBuilders.failureMessage().setMessage("用户不存在");
            }
            userManagerService.unlock(user.getId());
        }
        //解锁
        String loginCountUsername = LOGIN_COUNT + username;
        if (redisUtil.hasKey(loginCountUsername) && redisUtil.get(loginCountUsername).equals(LOCKED_FLAG)) {
            redisUtil.del(loginCountUsername);
            LOGGER.info("解锁成功,删除缓存用户登录错误次数信息");
        }
        return RestBuilders.successBuilder().build();
    }

    @ApiOperation("内部获取租户ID")
    @GetMapping(value = "/openapi/inner-token/{projectName}", produces = "application/json")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "内部获取租户ID")
    public RestMessage innerTokenByProjectName(@PathVariable(value = "projectName") String projectName) {
        if (StringUtils.isEmpty(projectName)) {
            return RestBuilders.failureMessage().setMessage("projectName 为空");
        }
        LinkappTenant linkappTenant = new LinkappTenant();
        linkappTenant.setPlatformProjectName(projectName);
        List<LinkappTenant> linkappTenants = linkappTenantService.selectLinkappTenantList(linkappTenant);
        if (linkappTenants == null || linkappTenants.size() <= 0) {
            return RestBuilders.failureMessage().setMessage("项目名称不存在");
        }
        Map<String, Set<String>> collect = linkappTenants.stream().collect(Collectors.groupingBy(LinkappTenant::getPlatformProjectName, Collectors.mapping(LinkappTenant::getId, Collectors.toSet())));
        return RestBuilders.successBuilder().data(collect).build();
    }

    @ApiOperation("内部获取租户ID")
    @GetMapping("/openapi/inner-token/user/{username}")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "内部获取租户ID")
    public RestMessage innerTokenByUsername(@PathVariable(value = "username") String username) {
        LinkappUser linkappUser = userService.findByUsername(username);
        if (linkappUser == null || linkappUser.getId() == null) {
            return RestBuilders.failureMessage().setMessage("用户不存在");
        }
        return RestBuilders.successBuilder().data("token", linkappUser.getTenantId()).build();
    }

    @ApiOperation("内部获取项目信息")
    @GetMapping(value = "/openapi/inner/project/{project}",produces = "application/json")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "内部获取项目信息")
    public RestMessage innerProjectByIdOrName(@PathVariable(value = "project") String project) {
        if (StringUtils.isEmpty(project)) {
            return RestBuilders.failureMessage().setMessage("project 为空");
        }
        RestMessage projectInfo = openApiService.getProjectInfo(project);
        return projectInfo;
    }

    @ApiOperation("内部获取项目信息")
    @GetMapping(value = "/openapi/inner/project",produces = "application/json")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "内部获取项目信息")
    public RestMessage innerProjectInfo(@ModelAttribute InnerProjectModel innerProjectModel) {
        RestMessage projectInfo = openApiService.getProjectInfo(innerProjectModel);
        return projectInfo;
    }

    /**
     * 在linkthings的接口api/schemeCopyProject/copy种调用该接口
     *
     * @param applicationCopyModel
     * @param response
     * @return
     * @throws IOException
     */
    @ApiOperation("应用拷贝")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "应用拷贝")
    @PostMapping(value = "/applicationCopy",produces = "application/json;charset=UTF-8")
    public RestMessage applicationCopy(@RequestBody AapplicationCopyModelDTO applicationCopyModel,HttpServletResponse response) throws IOException {
        OutputStream outputStream = response.getOutputStream();
        String responseString = JSONObject.toJSONString(RestBuilders.successBuilder("200").message("success").build());
        LOGGER.info("applicationCopy-被调用-线程:" + Thread.currentThread());
        outputStream.write(responseString.getBytes());
        outputStream.flush();
        outputStream.close();
        return RestBuilders.successBuilder(applicationCopyService.copy(applicationCopyModel)).build();
    }

    /**
     * 删除AEP
     * @return REST消息
     */
    @ApiOperation("删除AEP")
    @PostMapping("openapi/delete/{projectId}")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "删除AEP")
    public RestMessage deleteAep(@PathVariable("projectId")Long projectId) {
        //删除相应的表数据
        openApiService.deleteAep(projectId);
        return RestBuilders.successBuilder().build();
    }

    /**
     * 检查etl能耗统计
     *
     * @return REST消息
     */
    @ApiOperation("检查etl能耗统计")
    @PostMapping("openapi/checkErrorEtlStatistic")
    @CommonOperateLogAnnotate(module = LogModule.OPEN_API, desc = "检查etl能耗统计")
    public RestMessage checkErrorETLStatistic(@RequestBody Map<String, Object> esPostBody2) {
        etlStatisticMonitorService.checkErrorEtlStatistic(esPostBody2);
        return RestBuilders.successBuilder().build();
    }

    /**
     * 定时任务测试。定时采集
     *
     * @return
     */
    @ApiOperation("根据设备，分组统计各设备在查询时间内的能耗,根据时间各设备的折线图")
    @PostMapping("openapi/collectStatisticsEnergyGroupByDeviceByTimeScheduleTest")
    public RestMessage collectStatisticsEnergyGroupByDeviceByTimeScheduleTest() {
        return RestBuilders.successBuilder().data(esService.collectStatisticsEnergyGroupByDeviceByTimeSchedule()).build();
    }

    /**
     * 权限验证
     * @param request
     * @param signToString
     * @return
     */
    private RestMessage checkAuth(HttpServletRequest request, String signToString, Supplier<RestMessage> supplier) {
        String headerSign = request.getHeader("H-Ca-Signature").trim();
        String appkey = request.getHeader("H-App-Key").trim();
        QueryWrapper<Application> wrapper = new QueryWrapper<>();
        wrapper.eq("app_key", appkey);
        wrapper.eq("delete_state", 1);
        Application application = applicationService.getApplication(wrapper);
        String sign = DigestUtil.hmacSHA256Sign(signToString, application.getAppSecret()).trim();
        LOGGER.info("headerSign : " + headerSign);
        LOGGER.info("appkey : " + appkey);
        LOGGER.info("signToString : " + signToString);
        LOGGER.info("sign : " + sign);
        if (!sign.equalsIgnoreCase(headerSign)) {
            return RestBuilders.failureBuilder("认证失败").build();
        }
        return supplier.get();
    }

    /**
     * 定时任务测试。定时采集
     *
     * @param projectId
     * @return
     */
    @PostMapping("openapi/findAdminUserByProjectId")
    public RestMessage findAdminUserByProjectId(@RequestParam("projectId") String projectId) {
        Assert.isTrue(ObjectUtils.isNotEmpty(projectId), "项目id不能为空");
        return RestBuilders.successBuilder().data(linkappUserService.findAdminUserByProjectId(projectId)).build();
    }


    /**
     * 定时任务测试。定时采集
     *
     * @param user
     * @return
     */
    @PostMapping("openapi/forgetPassword")
    public RestMessage forgetPassword(HttpServletRequest request, @RequestBody User user) {
        String oauth = request.getHeader("Authorization");
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        //对比这两个密码是否是同一个密码
        boolean matches = passwordEncoder.matches(user.getPassword() + "easylinkin@2020", oauth);
        if (!matches) {
            throw new BusinessException("验证失败");
        }
        Assert.isTrue(ObjectUtils.isNotEmpty(user.getUsername()), "username 不能为空");
        Assert.isTrue(ObjectUtils.isNotEmpty(user.getPassword()), "password 不能为空");
        linkappUserService.forgetPassword(user.getUsername(), user.getPassword());
        return RestBuilders.successBuilder().build();
    }

    /**
     * 获取安全检查隐患完成数量情况
     *
     * @param safetyCheckHiddenDangerPageVo 安全检查隐患页面vo
     * @return 统一出参
     */
    @PostMapping("/openapi/safetyCheckHiddenCount")
    public RestMessage safetyCheckHiddenCount(@RequestBody SafetyCheckHiddenDangerPageVo safetyCheckHiddenDangerPageVo) {
        return hiddenDangerService.safetyCheckHiddenCount(safetyCheckHiddenDangerPageVo);
    }

    /***
     * 安全检查 -> 隐患新增 -> 参建单位
     * @param requestModel 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/laborCompanyProject/list")
    @ApiOperation("根据条件，分页(不分页)查询")
    public RestMessage queryListByPage(@RequestBody RequestModel<LaborCompanyProjectDTO> requestModel) {
        Assert.notNull(requestModel.getCustomQueryParams(), "customQueryParams 不能为空");
        Assert.notNull(requestModel.getPage(), "page 不能为空");
        IPage<LaborCompanyProjectDTO> record = laborCompanyProjectService.queryListByPage(requestModel);
        return RestBuilders.successBuilder().data(record).build();
    }

    /**
     * 安全检查 -> 隐患新增 ->安全隐患
     *
     * @param dangerType 隐患类型
     * @return 统一出参
     */
    @PostMapping("/openapi/danger/selectTreeWithType")
    @ApiOperation("查询隐患库+隐患类型组成的树")
    public RestMessage selectTreeWithType(@RequestBody DangerType dangerType) {
        Assert.notNull(dangerType, "customQueryParams 不能为空");
        List<DangerTypeNode> record = appDangerService.selectTreeWithType(dangerType);
        return RestBuilders.successBuilder(record).build();
    }

    /**
     * 安全检查 -> 隐患新增 ->部位
     * @Description: 根据条件，分页(不分页)查询
     * @author kan yuanfeng
     * @date 2020/11/04 11:42
     */
    @PostMapping("/openapi/qualityPosition/list")
    @ApiOperation("根据条件，分页(不分页)查询")
    public RestMessage queryList(@RequestBody QualityPositionDTO qualityPositionDTO) {
//        update 20220901 兼容质量部位查询 没传type默认是查质量
        if (null == qualityPositionDTO.getType()) {
            qualityPositionDTO.setType(1);
        }
        List<QualityPositionDTO> record = qualityPositionService.queryList(qualityPositionDTO);
        return RestBuilders.successBuilder().data(record).build();
    }

    /**
     * 安全检查 -> 隐患新增 ->用户信息
     * @param requestModel 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/linkappUser/selectPage")
    public RestMessage selectPage(@RequestBody RequestModel<LinkappUser> requestModel) {
        Assert.notNull(requestModel.getCustomQueryParams(), "customQueryParams 不能为空");
        Assert.notNull(requestModel.getPage(), "page 不能为空");
        IPage<LinkappUser> record = linkappUserService.selectUsersPage(requestModel.getPage(),
                requestModel.getCustomQueryParams());
        return RestBuilders.successBuilder().data(record).build();
    }

    /**
     * 新增安全检查隐患
     *
     * @param hiddenDanger 实体对象
     * @return 新增结果
     */
    @PostMapping("/openapi/safetyCheck/addHiddenDanger")
    @ApiOperation("新增")
    public RestMessage insert(@RequestBody HiddenDanger hiddenDanger) {
        return RestBuilders.successBuilder((this.hiddenDangerService.saveOne(hiddenDanger))).build();
    }

    /**
     * 获取安全检查隐患列表
     *
     * @param requestModel 安全检查隐患页面vo
     * @return 统一出参
     */
    @PostMapping("/openapi/hiddenDanger/getPage")
    public RestMessage safetyCheckHiddenList(@RequestBody RequestModel<HiddenDangerDTO> requestModel) {
        Assert.notNull(requestModel.getCustomQueryParams(), "customQueryParams 不能为空");
        Assert.notNull(requestModel.getPage(), "page 不能为空");

        IPage<HiddenDangerDTO> record = hiddenDangerService.selectListByPage(requestModel.getPage(),
                requestModel.getCustomQueryParams());

        return RestBuilders.successBuilder(record).build();
    }

    /**
     * 通过主键查询隐患详情
     * @param sourceType 类型
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("/openapi/hiddenDanger/{sourceType}/{id}")
    public RestMessage hiddenDangerSelectOne(@PathVariable Integer sourceType,@PathVariable Serializable id) {
        return RestBuilders.successBuilder(hiddenDangerService.getOneByIdAndSourceType(id,sourceType)).build();
    }

    /**
     * 隐患修改整改人
     *
     * @param hiddenDanger 实体对象
     * @return 修改结果
     */
    @PostMapping("/openapi/hiddenDanger/modifyRectifyUser")
    @ApiOperation("修改整改人")
    public RestMessage hiddenDangerModifyRectifyUser(@RequestBody HiddenDanger hiddenDanger) {
        return RestBuilders.successBuilder()
                .success(hiddenDangerService.modifyRectifyUser(hiddenDanger)).build();
    }

    /**
     * 隐患修改复查人
     *
     * @param hiddenDanger 实体对象
     * @return 修改结果
     */
    @PostMapping("/openapi/hiddenDanger/modifyCheckUser")
    @ApiOperation("修改整改人")
    public RestMessage hiddenDangerModifyCheckUser(@RequestBody HiddenDanger hiddenDanger) {
        return RestBuilders.successBuilder()
                .success(hiddenDangerService.modifyCheckUser(hiddenDanger)).build();
    }

    /**
     * 企业级检查台账数量统计
     *
     * @param requestModel 请求条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/hiddenDanger/getCountEnterprise")
    @ApiOperation("企业级检查台账数量统计")
    public RestMessage getCountEnterprise(@RequestBody RequestModel<HiddenDangerDTO> requestModel) {

        HiddenDangerCountDTO countDto = hiddenDangerService.getCountEnterprise(requestModel);
        return RestBuilders.successBuilder(countDto).build();
    }

    /**
     * 隐患数据按项目统计(企业级)
     *
     * @return 统计数据
     */
    @PostMapping("/openapi/hiddenDanger/getTenantIdCount")
    @ApiOperation("隐患数据按项目统计")
    public RestMessage getUnitIdCount(@RequestBody RequestModel<HiddenDangerDTO> requestModel) {
        IPage<HiddenDangerCountDTO> tentantIdCountIPage = hiddenDangerService.getTenantIdCount(requestModel);
        return RestBuilders.successBuilder(tentantIdCountIPage).build();
    }


    @PostMapping("/openapi/getDeviceVideoList")
    public RestMessage getDeviceVideoList(@RequestParam("projectId") Long projectId) {
        return RestBuilders.successBuilder().data(openApiService.getDeviceVideoList(projectId)).build();
    }

    @PostMapping("/openapi/getAepTenantInfo")
    public RestMessage getAepTenantInfo(@RequestParam("projectId") Long projectId) {
        return RestBuilders.successBuilder().data(openApiService.getAepTenantInfo(projectId)).build();
    }


    /**
     * 企业级日统计填报数据
     *
     * @param peopleNumAtFillinVo 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/peopleNumAtFillin/businessDayFillinData")
    @ApiOperation("企业级日统计填报数据")
    public RestMessage businessDayFillinData(@RequestBody PeopleNumAtFillinVo peopleNumAtFillinVo) {
        return appPeopleNumAtFillinService.businessDayFillinData(peopleNumAtFillinVo);
    }

    /**
     * 企业级日统计填报数据列表
     *
     * @param requestModel 查询分页对象
     * @return 所有数据
     */
    @PostMapping("/openapi/peopleNumAtFillin/selectDtoPage")
    @ApiOperation("企业级日统计填报数据列表")
    public RestMessage selectDtoPage(@RequestBody RequestModel<PeopleNumAtFillinVo> requestModel) {
        Assert.notNull(requestModel.getCustomQueryParams(), "customQueryParams 不能为空");
        Assert.notNull(requestModel.getPage(), "page 不能为空");
        return appPeopleNumAtFillinService.selectDtoPage(requestModel);
    }

    @PostMapping("/openapi/getCameraCountByProjectIds")
    public RestMessage getCameraCountByProjectIds(@RequestParam(value = "projectIds",required = false) List<Long> projectIds) {
        return RestBuilders.successBuilder().data(openApiService.getCameraCountByProjectIds(projectIds)).build();
    }

    /**
     * 当前现场人员统计/app企业级
     *
     * @param tenantId 租户id
     * @return 所有数据
     */
    @GetMapping("/openapi/enterpriseUser/projectUser")
    @ApiOperation("当前现场人员统计/app企业级")
    public RestMessage projectUser(String tenantId){
        //enterpriseUser/projectUser的这个方法业务逻辑写在controller，没有下层到service，只能这样复制过来
        List<LobarUserDTO> list = new ArrayList<>();
        RequestModel<UserProjectDTO> requestModel = new RequestModel<>();
        UserProjectDTO userProjectDTO = new UserProjectDTO();
        userProjectDTO.setTenantId(tenantId);
        userProjectDTO.setStartTime(DateUtil.beginOfDay(new Date()));
        requestModel.setCustomQueryParams(userProjectDTO);
        requestModel.setPage(new Page(0,-1));

        IPage<LinkappTenantDTO> iPage = lobarScreenService.countProject(requestModel);
        List<LobarUserDTO> dtoList = iPage.getRecords().stream()
                .flatMap(l -> l.getLobarUserDTOS().stream()).collect(Collectors.toList());
        EnterpriseUserProjectController.getUsers(list, dtoList,"项目部管理人员");
        EnterpriseUserProjectController.getUsers(list, dtoList,"其他管理人员");
        EnterpriseUserProjectController.getUsers(list, dtoList,"现场作业人员");
        return RestBuilders.successBuilder().data(list).build();
    }

    /**
     * 实时人员统计（出勤/在场）/app企业级
     */
    @GetMapping("/openapi/enterpriseUser/omNum")
    public RestMessage getOmNumByTid(String tenantId){
        List<LobarUserDTO> lobarUserDTOS = userProjectService.getOmNumByTid(tenantId);
        return RestBuilders.successBuilder().data(lobarUserDTOS).build();
    }

    /**
     * 防疫统计 app
     */
    @GetMapping("/openapi/enterpriseUser/app/epidemic")
    public RestMessage countAppEpidemic(){
        Map<String, Object> map = lobarScreenService.countAppEpidemic();
        return RestBuilders.successBuilder().data(map).build();
    }

    /**
     * 参建单位分析 app端
     */
    @GetMapping("/openapi/enterpriseUser/app/company")
    public RestMessage countAppCompany(){
        Map<String, Integer> map = lobarScreenService.countAppCompany();
        return RestBuilders.successBuilder().data(map).build();
    }
    /**
     * 近3个月安全检查分类
     *
     * @return
     */
    @GetMapping("/openapi/selectSafetyCheckCategory")
    @ApiOperation("安全检查分类 ")
    public RestMessage selectSafetyCheckCategory() {
        Date startTime = com.easylinkin.linkappapi.common.utils.DateUtil.addMonth(new Date(), -3);
        Date startTime1 = com.easylinkin.linkappapi.common.utils.DateUtil
            .getTodayStartTime(startTime);
        return RestBuilders.successBuilder().data(openApiService.selectSafetyCheckCategory(startTime1,new Date())).build();
    }

    /**
     * 近3个月企业检查，项目自检趋势图
     *
     * @return
     */
    @PostMapping("/openapi/selectSafetyCheckTrend")
    public RestMessage selectSafetyCheckTrend() {
        return RestBuilders.successBuilder().data(openApiService.selectSafetyCheckTrend()).build();
    }


    /**
     * 企业级大屏-检查分类
     *
     * @return
     */
    @PostMapping("/openapi/selectSafetyCheckCategoryByName")
    public RestMessage selectSafetyCheckCategoryByName(@RequestParam("start") String start, @RequestParam("end") String end) {
        return RestBuilders.successBuilder().data(
                openApiService.selectSafetyCheckCategoryByName(com.easylinkin.linkappapi.common.utils.DateUtil.getDateFromYYYYMMDDHHmmss(start),com.easylinkin.linkappapi.common.utils.DateUtil.getDateFromYYYYMMDDHHmmss(end))).build();
    }

    /**
     * 项目详情
     */
    @PostMapping("/openapi/enterpriseUser/project")
    public RestMessage countProject(@RequestBody RequestModel<UserProjectDTO> requestModel){
        IPage<LinkappTenantDTO> record = lobarScreenService.countProject(requestModel);
        return RestBuilders.successBuilder().data(record).build();
    }

    /**
     * 参建单位分析详情 app端
     */
    @PostMapping("/openapi/enterpriseUser/app/company/detail")
    public RestMessage countAppCompanyDetail(@RequestBody RequestModel<UserProjectDTO> requestModel){
        IPage<EnterpriseDTO> record = lobarScreenService.countAppCompanyDetail(requestModel);
        return RestBuilders.successBuilder().data(record).build();
    }

    /**
     * 防疫统计详情 app端
     */
    @PostMapping("/openapi/enterpriseUser/app/epidemic/detail")
    public RestMessage countAppEpidemicDetail(@RequestBody RequestModel<UserProjectDTO> requestModel){
        IPage<EpidemicDTO> record = lobarScreenService.countAppEpidemicDetail(requestModel);
        return RestBuilders.successBuilder().data(record).build();
    }

    /**
     * 企业级大屏-智能监测预警统计
     *
     * @return
     */
    @PostMapping("/openapi/selectAlarmStatistic")
    public RestMessage selectAlarmStatistic(@RequestParam("start") String start, @RequestParam("end") String end) {
        List<BigScreenStatisticDTO> list = openApiService.selectAlarmStatistic(com.easylinkin.linkappapi.common.utils.DateUtil.getDateFromYYYYMMDDHHmmss(start), com.easylinkin.linkappapi.common.utils.DateUtil.getDateFromYYYYMMDDHHmmss(end));
        return RestBuilders.successBuilder().data(list).build();
    }

    /**
     * 企业级大屏-危大工程分类
     *
     * @return
     */
    @PostMapping("/openapi/selectDangerousStatistic")
    public RestMessage selectDangerousStatistic(@RequestBody DangerousInfo dangerous) {
        List<BigScreenStatisticDTO> list = openApiService.selectDangerousStatistic(dangerous);
        return RestBuilders.successBuilder().data(list).build();
    }


    /**
     * 企业级大屏-项目列表
     *
     * @return
     */
    @PostMapping("/openapi/selectProjectStatisticList")
    public RestMessage selectProjectStatisticList(@RequestBody ProjectDTO projectDTO) {
        List<ProjectStatisticDTO> list = openApiService.selectProjectStatisticList(projectDTO);
        return RestBuilders.successBuilder().data(list).build();
    }

    /**
     * 查询租户列表
     * @param linkappTenant 租户信息
     * @return 统一出参
     */
    @ApiOperation("查询租户列表")
    @PostMapping("/openapi/tenant/selectLinkappTenantList")
    public RestMessage selectLinkappTenantList(@RequestBody LinkappTenant linkappTenant) {
        return RestBuilders.successBuilder().data(linkappTenantService.selectLinkappTenantList(linkappTenant)).build();
    }

    /**
     * 导出检查记录表/整改通知书
     * 业务没有下层到service做，就这样复制过来改改
     *
     */
    @GetMapping("/openapi/enterpriseSafetyCheckHiddent/exportWord/{type}")
    @ApiOperation("导出检查记录表/整改通知书")
    public void exportById(@RequestHeader("User-Agent") String header,HttpServletResponse response,
                           @PathVariable("type")Integer type,Integer wordType,@RequestParam("checkId") Long checkId,String tenantId)
            throws Exception {
        //获取并组织excel数据
        QueryWrapper<HiddenDanger> hiddenDangerQw = new QueryWrapper<>();
        hiddenDangerQw.eq("enterprise_safety_check_id",checkId);
        hiddenDangerQw.orderByAsc("create_time");
        List<HiddenDanger> hiddenDangerList = hiddenDangerService.getBaseMapper().selectList(hiddenDangerQw);
        List<String> ids = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(hiddenDangerList)){
            ids = hiddenDangerList.stream().map(e -> e.getId()).collect(Collectors.toList());
        }

        XWPFDocument doc = hiddenDangerService.getWord(type,wordType,ids,tenantId);

        String filename;
        // 当前日期，用于导出文件名称
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String s = (type==1?"检查记录表-":"整改通知书-")+sdf.format(new Date());
        if(header.contains("Firefox")){
            //说明是火狐浏览器,使用Base64Encoder类进行编码
            filename = "=?utf-8?B?"+ Base64.encode(s.getBytes(StandardCharsets.UTF_8))+"?=";
        }else{
            //是其他浏览器,使用URLEncoder类进行编码
            filename = String.valueOf(URLEncoder.encode(s, "UTF-8"));
        }

        // 指定下载的文件名--设置响应头
        response.setHeader("Content-Disposition", "attachment;filename=" +filename+".docx");
        response.setContentType("application/msword;charset=UTF-8");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        // 写出数据输出流到页面
        OutputStream output = response.getOutputStream();
        BufferedOutputStream bufferedOutPut = new BufferedOutputStream(output);
        doc.write(bufferedOutPut);
        bufferedOutPut.flush();
        bufferedOutPut.close();
        output.close();
    }

    /**
     * 企业级查询分页
     *
     * @param requestModel 查询分页对象
     * @return 所有数据
     */
    @PostMapping("/openapi/quality/actual/type/enterpriseGetPage")
    @ApiOperation("企业级查询分页")
    public RestMessage enterpriseGetPage(@RequestBody RequestModel<ActualMeasureTypeVo> requestModel) {
        Assert.notNull(requestModel.getCustomQueryParams(), "customQueryParams 不能为空");
        List<ActualMeasureType> record = actualMeasureTypeService.enterpriseGetPage(requestModel.getPage(), requestModel.getCustomQueryParams());
        return RestBuilders.successBuilder(record).build();
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("/openapi/quality/actual/type/{id}")
    @ApiOperation("实测实量分类查询单条")
    public RestMessage selectOne(@PathVariable Serializable id) {
        return RestBuilders.successBuilder(actualMeasureTypeService.getOneById(id)).build();
    }

    /**
     * 实测实量分类新增数据
     *
     * @param actualMeasureTypeVo 实体对象
     * @return 新增结果
     */
    @PostMapping("/openapi/quality/actual/type/add")
    @ApiOperation("新增实测实量分类")
    public RestMessage addActualType(@RequestBody ActualMeasureTypeVo actualMeasureTypeVo) {
        return actualMeasureTypeService.addActualType(actualMeasureTypeVo);
    }
    /**
     * 编辑实测实量分类
     *
     * @param actualMeasureTypeVo 实体对象
     * @return 新增结果
     */
    @PostMapping("/openapi/quality/actual/type/edit")
    @ApiOperation("编辑实测实量分类")
    public RestMessage editActualType(@RequestBody ActualMeasureTypeVo actualMeasureTypeVo) {
        return actualMeasureTypeService.editActualType(actualMeasureTypeVo);
    }

    /**
     * 批量删除实测实量分类
     *
     * @param idList 主键结合
     * @return 删除结果
     */
    @DeleteMapping("/openapi/quality/actual/type/batchDeleteType")
    @ApiOperation("批量删除实测实量分类")
    public RestMessage batchDeleteType(@RequestParam("idList") List<Long> idList) {
        return RestBuilders.successBuilder().success(this.actualMeasureTypeService.deleteByIds(idList)).build();
    }

    /**
     * 分页查询所有数据
     *
     * @param requestModel 查询分页对象
     * @return 所有数据
     */
    @PostMapping("/openapi/quality/actual/item/getPage")
    @ApiOperation("实测实量算法列表")
    public RestMessage actualItemGetPage(@RequestBody RequestModel<ActualMeasureItem> requestModel) {
        Assert.notNull(requestModel.getCustomQueryParams(), "customQueryParams 不能为空");
        Assert.notNull(requestModel.getPage(), "page 不能为空");
        IPage<ActualMeasureItem> record = actualMeasureItemService.selectPage(requestModel.getPage(), requestModel.getCustomQueryParams());
        return RestBuilders.successBuilder(record).build();
    }
    /**
     * 实测实量新增算法
     *
     * @param actualMeasureItemVo 实体对象
     * @return 新增结果
     */
    @PostMapping("/openapi/quality/actual/item/add")
    @ApiOperation("实测实量新增算法")
    public RestMessage addActualItem(@RequestBody ActualMeasureItemVo actualMeasureItemVo) {
        return actualMeasureItemService.addActualItem(actualMeasureItemVo);
    }

    /**
     * 实测实量算法详情
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("/openapi/quality/actual/item/{id}")
    @ApiOperation("实测实量算法详情")
    public RestMessage actualItemDetail(@PathVariable Serializable id) {
        return RestBuilders.successBuilder(actualMeasureItemService.getOneById(id)).build();
    }
    /**
     * 实测实量算法修改
     *
     * @param actualMeasureItemVo 实体对象
     * @return 修改结果
     */
    @PutMapping("/openapi/quality/actual/item/edit")
    @ApiOperation("实测实量算法修改")
    public RestMessage editActualItem(@RequestBody ActualMeasureItemVo actualMeasureItemVo) {
        //修改暂时不需要特殊逻辑
        ActualMeasureItem actualMeasureItem = new ActualMeasureItem();
        BeanUtil.copyProperties(actualMeasureItemVo,actualMeasureItem, CopyOptions.create().setIgnoreNullValue(true));
        actualMeasureItem.setModifyTime(DateUtil.date());
        actualMeasureItem.setModifier("0");
        return RestBuilders.successBuilder().success(actualMeasureItemService.updateOne(actualMeasureItem)).build();
    }
    /**
     * 批量删除实测实量算法
     *
     * @param idList 主键结合
     * @return 删除结果
     */
    @DeleteMapping("/openapi/quality/actual/item/batchDeleteItem")
    @ApiOperation("批量删除实测实量算法")
    public RestMessage batchDeleteItem(@RequestParam("idList") List<Long> idList) {
        return RestBuilders.successBuilder().success(actualMeasureItemService.deleteByIds(idList)).build();
    }

    @GetMapping("/openapi/getDashboardUrlByProjectIds")
    @ApiOperation("查询项目大屏地址,通过项目Id")
    public List<ProjectRefDashboard> getDashboardUrlByProjectIds(@RequestParam List<Long> ids) {
        return tenantMapper.getDashboardUrlByProjectIds(ids);
    }

    /**
     * 质量大屏检查趋势
     * @param qualityScreenPageVo 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/enterprise/qualityScreen/qualityCheckTrend")
    @ApiOperation("质量大屏检查趋势")
    public RestMessage qualityCheckTrend(@RequestBody QualityScreenPageVo qualityScreenPageVo){
        return qualityInspectionAccountService.qualityCheckTrend(qualityScreenPageVo);
    }
    /**
     * 检查分析-根据一级名称分类统计
     * @param qualityScreenPageVo 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/enterprise/qualityScreen/countByFirstLevelProblemName")
    @ApiOperation("检查分析-根据一级名称分类统计")
    public RestMessage countByFirstLevelProblemName(@RequestBody QualityScreenPageVo qualityScreenPageVo){
        return qualityInspectionAccountService.countByFirstLevelProblemName(qualityScreenPageVo);
    }
    /**
     * 分包单位排名
     * @param qualityScreenPageVo 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/enterprise/qualityScreen/laborQuestionRanking")
    @ApiOperation("分包单位排名")
    public RestMessage laborQuestionRanking(@RequestBody QualityScreenPageVo qualityScreenPageVo){
        return qualityQuestionInfoService.laborQuestionRanking(qualityScreenPageVo);
    }
    /**
     * 测量分类排名
     * @param qualityScreenPageVo 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/enterprise/qualityScreen/actualMeasureTypeCount")
    @ApiOperation("测量分类排名")
    public RestMessage actualMeasureTypeCount(@RequestBody QualityScreenPageVo qualityScreenPageVo){
        return actualMeasureTypeService.actualMeasureTypeCount(qualityScreenPageVo);
    }
    /**
     * 优秀施工滚播
     * @param qualityScreenPageVo 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/enterprise/qualityScreen/excellentAlbumRollShow")
    @ApiOperation("优秀施工滚播")
    public RestMessage excellentAlbumRollShow(@RequestBody QualityScreenPageVo qualityScreenPageVo){
        Page page = new Page();
        page.setCurrent(qualityScreenPageVo.getPage());
        page.setSize(qualityScreenPageVo.getSize());
        QualityAppraisingExcellentPhotoAlbumQueryDTO queryDTO = new QualityAppraisingExcellentPhotoAlbumQueryDTO();
        queryDTO.setEnterpriseSourceType(2);

        IPage<QualityAppraisingExcellentPhotoAlbumDTO> record = qualityAppraisingExcellentService.selectPhotoAlbumByPage(page,queryDTO);

        return RestBuilders.successBuilder(record).build();
    }

    /**
     * 项目详情滚播
     * @param qualityScreenPageVo 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/enterprise/qualityScreen/projectDetailRollShow")
    @ApiOperation("项目详情滚播")
    public RestMessage projectDetailRollShow(@RequestBody QualityScreenPageVo qualityScreenPageVo){
        return actualMeasureTypeService.projectDetailRollShow(qualityScreenPageVo);
    }

    /**
     * 实测实量排名
     * @param qualityScreenPageVo 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/enterprise/qualityScreen/actualMeasureCountTop")
    @ApiOperation("实测实量排名")
    public RestMessage actualMeasureCountTop(@RequestBody QualityScreenPageVo qualityScreenPageVo){
        return actualMeasureTypeService.actualMeasureCountTop(qualityScreenPageVo);
    }

    /**
     * 主要指标
     * @param qualityScreenPageVo 条件vo
     * @return 统一出参
     */
    @PostMapping("/openapi/enterprise/qualityScreen/mainIndexCount")
    @ApiOperation("主要指标")
    public RestMessage mainIndexCount(@RequestBody QualityScreenPageVo qualityScreenPageVo){
        return actualMeasureTypeService.mainIndexCount(qualityScreenPageVo);
    }

}
